﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Text;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using Microsoft.SharePoint;
using Microsoft.SharePoint.WebPartPages;
using Navigant.Application;
using Navigant.Common;
using Navigant.Infrastructure.Cases;
using Navigant.Infrastructure.Helpers;
using Navigant.Model.Cases;
using Navigant.Model.Custodians;

namespace Navigant.Web.UI
{
    public class PreservationNoticeSenderWebPart : CustodianWebPart
    {
        #region Constants

        private static class Constants
        {
            public const string UseCustodianPagingSettingName = "UseCustodianPaging";
            public const int PageSizeDefault = 50;
            public const string NameTooltip = "Searches on the Title field value of the Custodians list";
        }

        #endregion

        #region Fields

        private PagedList<Custodian> custodians;
		private HtmlTable layoutTable;
		private SenderControl senderControl;
		private CustodianSendList custodianSendList;
		private EventHistoryList eventHistoryList;
        private ICase currentCase;
        private CustodianService service;
        private int totalCustodians;
        private bool pageCustodians;
        private LinkButton nextLinkButton;
        private LinkButton previousLinkButton;
        private Table pagerTable;
        private TextBox custodianSearchTextBox;
        private Button custodianSearchButton;
        private Button clearSearchResultsButton;
        private bool searchButtonClicked;

        #endregion

        #region Properties

        [DefaultValue(300),
        WebPartStorage(Storage.Shared),
        FriendlyName("Scroll Height")]
        public int ScrollHeight { get; set; }

        [DefaultValue(Constants.PageSizeDefault),
        WebPartStorage(Storage.Shared),
        FriendlyName("Page Size")]
        public int PageSize { get; set; }

        [Browsable(false),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
        WebPartStorage(Storage.None)]
        public int CurrentPage
        {
            get
            {
                if (ViewState["currentPage"] != null)
                {
                    return (int)ViewState["currentPage"];
                }
                else
                {
                    return 0;
                }
            }
            set
            {
                ViewState["currentPage"] = value;
            }
        }

        [Browsable(false),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
        WebPartStorage(Storage.None)]
        public int LastCustodianItemId
        {
            get
            {
                if (ViewState["lastCustodianItemId"] != null)
                {
                    return (int)ViewState["lastCustodianItemId"];
                }
                else
                {
                    return 0;
                }
            }
            set
            {
                ViewState["lastCustodianItemId"] = value;
            }
        }

        private string NextPageInformation
        {
            get
            {
                if (ViewState["nextPageInformation"] != null)
                {
                    return (string)ViewState["nextPageInformation"];
                }
                return null;
            }
            set
            {
                ViewState["nextPageInformation"] = value;
            }
        }

        private string PreviousPageInformation
        {
            get
            {
                if (ViewState["previousPageInformation"] != null)
                {
                    return (string)ViewState["previousPageInformation"];
                }
                return null;
            }
            set
            {
                ViewState["previousPageInformation"] = value;
            }
        }

        private string CurrentPageInformation
        {
            get
            {
                if (ViewState["currentPageInformation"] != null)
                {
                    return (string)ViewState["currentPageInformation"];
                }
                return null;
            }
            set
            {
                ViewState["currentPageInformation"] = value;
            }
        }

        private string SearchText
        {
            get
            {
                if (ViewState["searchText"] != null)
                {
                    return (string)ViewState["searchText"];
                }
                return null;
            }
            set
            {
                ViewState["searchText"] = value;
            }
        }

        #endregion

        #region OnInit

        protected override void OnInit(EventArgs e)
		{
            base.OnInit(e);
			try
			{
                this.currentCase = CaseService.GetCaseBy(new Uri(SPContext.Current.Web.Url));
                this.service = new CustodianService(this.currentCase);
                this.pageCustodians = ConfigurationSettingsHelper.GetBoolean(currentCase, Constants.UseCustodianPagingSettingName);
                this.searchButtonClicked = false;

				this.layoutTable = new HtmlTable();
				this.layoutTable.CellSpacing = 10;
				this.layoutTable.CellPadding = 0;
				this.layoutTable.Border = 0;
				this.Controls.Add(this.layoutTable);

				HtmlTableRow row = new HtmlTableRow();
				this.layoutTable.Rows.Add(row);

				HtmlTableCell cell = new HtmlTableCell();
				cell.ColSpan = 2;
				row.Cells.Add(cell);

				this.senderControl = new SenderControl();
                this.senderControl.SendNotices += new EventHandler(this.SendNotices);
				cell.Controls.Add(this.senderControl);

				#region Custodian Search

                row = new HtmlTableRow();
                this.layoutTable.Rows.Add(row);

                cell = new HtmlTableCell();
                cell.ColSpan = 2;
				cell.Style.Add("vertical-align", "top");
				row.Cells.Add(cell);
                Table searchTable = new Table();
                cell.Controls.Add(searchTable);
                TableRow searchRow = new TableRow();
                searchTable.Rows.Add(searchRow);
                TableCell nameLabelSearchCell = new TableCell();
                cell.Align = "left";
                nameLabelSearchCell.Text = "Last Name:";
                nameLabelSearchCell.ToolTip = Constants.NameTooltip;
                searchRow.Cells.Add(nameLabelSearchCell);
                TableCell nameValueSearchCell = new TableCell();
                nameValueSearchCell.ToolTip = Constants.NameTooltip;
                this.custodianSearchTextBox = new TextBox();
                nameValueSearchCell.Controls.Add(this.custodianSearchTextBox);
                searchRow.Cells.Add(nameValueSearchCell);
                TableCell nameButtonSearchCell = new TableCell();
                this.custodianSearchButton = new Button();
                this.custodianSearchButton.Text = "Search";
                this.custodianSearchButton.Click += new EventHandler(this.custodianSearchButton_Click);
                nameButtonSearchCell.Controls.Add(this.custodianSearchButton);
                searchRow.Cells.Add(nameButtonSearchCell);
                TableCell clearSearchResultsCell = new TableCell();
                this.clearSearchResultsButton = new Button();
                this.clearSearchResultsButton.Text = "Clear Search Results";
                this.clearSearchResultsButton.Click += new EventHandler(this.clearSearchResultsButton_Click);
                clearSearchResultsCell.Controls.Add(this.clearSearchResultsButton);
                searchRow.Cells.Add(clearSearchResultsCell);

                #endregion

                row = new HtmlTableRow();
                this.layoutTable.Rows.Add(row);

                cell = new HtmlTableCell();
                cell.Style.Add("vertical-align", "top");
                row.Cells.Add(cell);

                if (this.ScrollHeight == 0)
                {
                    this.ScrollHeight = 300;
                }
                this.custodianSendList = new CustodianSendList(this.currentCase, this.ScrollHeight, this.pageCustodians);
				cell.Controls.Add(this.custodianSendList);

				cell = new HtmlTableCell();
				cell.Style.Add("vertical-align", "top");
				row.Cells.Add(cell);

                #region Paging Table

                if (this.pageCustodians)
                {
                    this.pagerTable = new Table();
                    this.Controls.Add(this.pagerTable);

                    TableRow tr = new TableRow();
                    tr.CssClass = "ms-WPHeader";
                    this.pagerTable.Rows.Add(tr);

                    TableCell td = new TableCell();
                    td.HorizontalAlign = HorizontalAlign.Right;
                    tr.Cells.Add(td);

                    HtmlGenericControl div = new HtmlGenericControl("div");
                    this.previousLinkButton = new LinkButton();
                    this.previousLinkButton.ID = "lbPrev";
                    this.previousLinkButton.Text = "< Prev";
                    this.previousLinkButton.Click += new EventHandler(previousLinkButton_Click);
                    div.Controls.Add(this.previousLinkButton);
                    div.Style["margin-right"] = "10px";
                    div.Style["display"] = "inline";
                    td.Controls.Add(div);

                    div = new HtmlGenericControl("div");
                    this.nextLinkButton = new LinkButton();
                    this.nextLinkButton.ID = "lbNext";
                    this.nextLinkButton.Text = "Next >";
                    this.nextLinkButton.Click += new EventHandler(nextLinkButton_Click);
                    div.Style["margin-right"] = "10px";
                    div.Style["display"] = "inline";
                    div.Controls.Add(this.nextLinkButton);
                    td.Controls.Add(div);

                    if (this.custodians != null)
                    {
                        this.pagerTable.Width = new Unit(100, UnitType.Percentage);
                        this.pagerTable.BorderStyle = BorderStyle.Solid;
                        this.pagerTable.Style["border-top-style"] = "none";
                        this.pagerTable.BorderWidth = new Unit(1, UnitType.Pixel);
                        this.pagerTable.BorderColor = Color.Black;
                    }
                }

                #endregion

                this.eventHistoryList = new EventHistoryList(this.ScrollHeight);
				cell.Controls.Add(this.eventHistoryList);
			}
			catch (Exception ex)
			{
				Logger.LogError(ex, this.currentCase);
				this.WriteErrorToPage(ex);
			}
		}

        #endregion

        #region OnLoad

        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);
            if (!this.Page.IsPostBack)
            {
                this.CurrentPage = 0;
                SPSecurity.RunWithElevatedPrivileges(delegate()
                {
                    this.BindCustodians();
                });
            }
        }

        #endregion

        #region custodianSearchButton_Click

        private void custodianSearchButton_Click(object sender, EventArgs e)
        {
            this.searchButtonClicked = true;
            if (!string.IsNullOrEmpty(this.custodianSearchTextBox.Text))
            {
                this.SearchText = this.custodianSearchTextBox.Text;
                if (this.PageSize == 0)
                {
                    this.PageSize = Constants.PageSizeDefault;
                }
                IList<Custodian> unPagedCustodians = this.GetCaseCustodiansSearch();
                this.custodians = new PagedList<Custodian>(unPagedCustodians,
                    this.CurrentPage, this.PageSize, unPagedCustodians.Count);
                this.BindCustodians();
            }
        }

        #endregion

        #region clearSearchResultsButton_Click

        private void clearSearchResultsButton_Click(object sender, EventArgs e)
        {
            SPSecurity.RunWithElevatedPrivileges(delegate()
            {
                this.ClearSearch();
                this.BindCustodians();
            });
        }

        #endregion

        #region nextLinkButton_Click

        private void nextLinkButton_Click(object sender, EventArgs e)
        {
            this.CurrentPage += 1;
            SPSecurity.RunWithElevatedPrivileges(delegate()
            {
                this.BindCustodians();
            });
        }

        #endregion

        #region previousLinkButton_Click

        private void previousLinkButton_Click(object sender, EventArgs e)
        {
            this.CurrentPage -= 1;
            SPSecurity.RunWithElevatedPrivileges(delegate()
            {
                this.BindCustodians();
            });
        }

        #endregion

        #region BindCustodians

        private void BindCustodians()
        {
            if (this.PageSize == 0)
            {
                this.PageSize = Constants.PageSizeDefault;
            }
            if (this.pageCustodians)
            {
                if (!this.searchButtonClicked)
                {
                    // See if there was a search entered previously
                    if (!string.IsNullOrEmpty(this.SearchText))
                    {
                        IList<Custodian> unPagedCustodians = this.GetCaseCustodiansSearch();
                        this.custodians = new PagedList<Custodian>(unPagedCustodians,
                            this.CurrentPage, this.PageSize, unPagedCustodians.Count);
                    }
                    else
                    {
                        this.custodians = new PagedList<Custodian>(service.GetAllCustodiansPaged(this.PageSize,
                            this.CurrentPage, this.LastCustodianItemId, out this.totalCustodians),
                            this.CurrentPage, this.PageSize, this.totalCustodians, true);
                    }
                }
                if (this.custodians != null)
                {
                    if (this.custodians.Count > 0)
                    {
                        this.LastCustodianItemId = this.custodians[this.custodians.Count - 1].Id;
                    }
                    this.pagerTable.Visible = true;
                    this.previousLinkButton.Visible = this.custodians.HasPreviousPage;
                    this.nextLinkButton.Visible = this.custodians.HasNextPage;
                    this.pagerTable.Visible = (this.nextLinkButton.Visible || this.previousLinkButton.Visible);
                }
                else
                {
                    this.pagerTable.Visible = false;
                }
            }
            else
            {
                if (!this.searchButtonClicked)
                {
                    // See if there was a search entered previously
                    if (this.custodianSearchTextBox != null && 
                        !string.IsNullOrEmpty(this.custodianSearchTextBox.Text))
                    {
                        IList<Custodian> unPagedCustodians = this.GetCaseCustodiansSearch();
                        this.custodians = new PagedList<Custodian>(unPagedCustodians,
                            this.CurrentPage, unPagedCustodians.Count, unPagedCustodians.Count);
                    }
                    else
                    {
                        IList<Custodian> unPagedCustodians = this.service.FindAll();
                        this.custodians = new PagedList<Custodian>(unPagedCustodians,
                            this.CurrentPage, unPagedCustodians.Count, unPagedCustodians.Count);
                    }
                }
            }
            this.custodianSendList.SetCustodians(this.custodians);
            this.eventHistoryList.SetHistoryCustodian(this.custodianSendList.HistoryCustodian);
        }

        #endregion

        #region GetCaseCustodiansSearch

        private IList<Custodian> GetCaseCustodiansSearch()
        {
            CustodianService service = new CustodianService(this.currentCase);
            return service.GetCustodiansBy("Title", this.SearchText, true);
        }

        #endregion

        #region DisplayMessage

        private void DisplayMessage(string message)
        {
            this.DisplayMessage(message, false);
        }

        private void DisplayMessage(string message, bool error)
		{
			HtmlTableRow row = new HtmlTableRow();
			this.layoutTable.Rows.Add(row);

			HtmlTableCell cell = new HtmlTableCell();
			cell.ColSpan = 2;
            cell.Controls.Add(new LiteralControl(message));
			cell.Style.Add("color", error ? "red": "green");
			row.Cells.Add(cell);
		}

        #endregion

        #region SendNotices

        private void SendNotices(object sender, EventArgs e)
        {
            SPSecurity.RunWithElevatedPrivileges(delegate()
            {
                this.BindCustodians();
                List<Custodian> selectedCustodians = new List<Custodian>(this.custodianSendList.SelectedCustodians);
                bool hasInvalidEmailAddresses = false;
                EmailValidationResults results = null;
                foreach (Custodian custodian in selectedCustodians)
                {
                    results = EmailValidator.ValidateEmailAddress(custodian.Email);
                    if (results.Result != EmailValidationResult.Valid)
                    {
                        hasInvalidEmailAddresses = true;
                        break;
                    }
                }

                if (selectedCustodians.Count == 0)
                {
                    this.DisplayMessage("No custodians have been selected", true);
                }
                else if (string.IsNullOrEmpty(this.senderControl.FromAddress))
                {
                    this.DisplayMessage("Sender email address cannot be blank.", true);
                }
                else if (this.senderControl.FromAddress.IndexOf(" ") > -1)
                {
                    this.DisplayMessage("Sender email address cannot contain spaces.", true);
                }
                else if (hasInvalidEmailAddresses)
                {
                    this.DisplayMessage(string.Format("There were one or more custodians with invalid email addresses ({0}).",
                        results.Details), true);
                }
                else
                {
                    IList<Custodian> custodiansWithSendError = null;
                    try
                    {
                        SPSecurity.RunWithElevatedPrivileges(delegate()
                        {
                            custodiansWithSendError = PreservationNoticeSendingService.SendNotices(this.currentCase,
                                selectedCustodians, this.senderControl.NoticeId,
                                this.senderControl.FromAddress);
                        });

                        if (custodiansWithSendError != null && custodiansWithSendError.Count > 0)
                        {
                            StringBuilder message = new StringBuilder(100);
                            if (custodiansWithSendError != null && custodiansWithSendError.Count > 0)
                            {
                                message.Append("There was an error sending the notice(s) to the following Custodian(s):");
                                foreach (Custodian custodian in custodiansWithSendError)
                                {
                                    message.Append("</br>");
                                    message.Append(custodian.Name.FullName);
                                }
                            }
                            this.DisplayMessage(message.ToString(), true);
                        }
                        else
                        {
                            this.DisplayMessage("Preservation notice(s) sent.");
                            foreach (Custodian custodian in selectedCustodians)
                            {
                                this.custodianSendList.ClearCustodianSelection(custodian);
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        Logger.LogError(ex, this.currentCase);
                        this.DisplayMessage("There was an error sending the notice(s)", true);
                    }
                }
                //this.ClearSearch();
            });
        }

        #endregion

        #region ClearSearch

        private void ClearSearch()
        {
            if (this.custodianSearchTextBox != null)
            {
                this.custodianSearchTextBox.Text = string.Empty;
            }
            this.SearchText = null;
        }

        #endregion
    }
}
